home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / program / 177 / pascal / fastread.doc < prev    next >
Encoding:
Text File  |  1987-09-16  |  12.3 KB  |  412 lines

  1.      1    1    1    1    1    1    1    1    1    1    1    1    ]    ]
  2.  
  3.  
  4.                     Eric's Fast Text Readln
  5.                         By Eric W. Wedaa
  6.                         4620 E 17th St.
  7.                         Tucson AZ, 85711
  8.                           Bix :EWedaa
  9.                         CIS :76515.2274
  10.  
  11.  
  12.  
  13.      I'll be honest here.  I LOVE Pascal.  It's a nice neat little 
  14.  
  15. language for writting programs, quite unlike some of the anarchist 
  16.  
  17. languages (C, assembly) or dinosaurs (B.A.S.I.C.)  But there are 
  18.  
  19. times when even I'll admit that Personal Pascal has problems.  The 
  20.  
  21. most glaring problem is doing a READ or a READLN.  
  22.  
  23.  
  24.      Now don't get me wrong, they work just fine in most 
  25.  
  26. instances.  But they can be the most annoying function of Pascal 
  27.  
  28. when I have to read in 200K of text file from a RAM disk, or even 
  29.  
  30. worse, 200K off of a floppy disk. I can go to the coffee shop for 
  31.  
  32. lunch while I'm reading in all that text.  Thankfully, O.S.S. has 
  33.  
  34. given us an extension that lets us call some of the GEMDOS 
  35.  
  36. routines from our code.
  37.  
  38.  
  39.                         My New Routines
  40.  
  41.      Well, I finally got sick of going to the coffee shop all the 
  42.  
  43. time.  (The waitress's avoid me now, since they all know I'm a 
  44.  
  45. lousy tipper.)  In the FASTREAD folder on the disk, you'll find 
  46.  
  47. my answer to the coffee shop blues.  This program is a Pascal 
  48.  
  49. version of GEMDOS $3C, $3D, $3E, $3F, $40 (Create, Open, Close, 
  50.  
  51. Read, Write).  Using these routines in your program will make 
  52.  
  53. your READLN's between 7 and 12 times faster than the Pascal 
  54.  
  55. supplied READLN.
  56.  
  57.  
  58.                        Using the Routines
  59.  
  60.      For those of you interested in just using these routines, 
  61.  
  62. this section is all you'll ever need to know.  You'll need to put 
  63.  
  64. the constants, types, and the routines from FASTREAD.PAS into your 
  65.  
  66. program.  Allthough they don't need to be global for your program, 
  67.  
  68. they do need to be declared in the same block of code that you'll 
  69.  
  70. be using the routines from.  (Which probably means globally.)
  71.  
  72.  
  73.      Now when you want to have a file for just reading from the 
  74.  
  75. disk, instead of declaring it as type FILE OF TEXT, just declare 
  76.  
  77. it instead as type BUFFER.  Whenever you want to perform an action 
  78.  
  79. a disk file, just use the matching function from the chart below.  
  80.  
  81. You will still be passing parameters in the same order as with the 
  82.  
  83. Pascal functions.  The two error routines require you to pass the 
  84.  
  85. buffer to them as well.  You MUST do your own error checking with 
  86.  
  87. these routines!
  88.  
  89.  
  90.      Fast Read Subroutines
  91.  
  92.      Pascal                                 Fast Read
  93.      Rewrite (File of TEXT, File name)      F_Rewrite(Buffer, File name)
  94.      Writeln (File of TEXT, String)         F_Writeln(Buffer, String)
  95.      Write   (File of TEXT, String)         F_Write(Buffer, String)
  96.      Reset   (File of TEXT, File name)      F_Reset (Buffer, File name)    
  97.      Readln  (File of TEXT, String)         F_Readln (Buffer, String)     
  98.      Close   (File of TEXT)                 F_Close (Buffer)     
  99.      Eof     (File of TEXT)                 F_Eof (Buffer)  
  100.      IO_Result                              F_Io_Result (Buffer)
  101.                                             F_Error (Buffer)
  102.  
  103.  
  104.      Notice though that these routines are set up just for 
  105.  
  106. READING or WRITING from or to a disk based file. (Ram, Hard, or 
  107.  
  108. Floppy disk.)  This is not for reading from any of the ports, or 
  109.  
  110. more likely, to try to write to any of the ports.
  111.  
  112.  
  113.      If you don't want to be reading in 255 byte strings, change 
  114.  
  115. the STRING_SIZE constant to the right size.
  116.  
  117.  
  118.                         Why it's Faster
  119.  
  120.      Doing a F_Readln or F_Writeln is increadibly fast.  7 to 12 
  121.  
  122. times faster in some cases.  Great, but why?  It has mainly to do 
  123.  
  124. with two areas we can't touch.  The first is the file buffer 
  125.  
  126. size.
  127.  
  128.  
  129.      When you declare a text file, Pascal only sets aside a small 
  130.  
  131. area of memory as a file buffer.  When it's used, it has to call 
  132.  
  133. the disk up again and read another sector or two.  In other words, 
  134.  
  135. it's always calling the disk, which entails spinning up the drive, 
  136.  
  137. finding the sector, reading the sector, and turning the drive off.  
  138.  
  139.  
  140.      When you use the Fast Read routines, we try and avoid the 
  141.  
  142. time spinning up the disk and searching for tracks and sectors 
  143.  
  144. from a stopped disk.  Instead of reading or writing in 512 bytes 
  145.  
  146. at a time, we read or write in 15,000 bytes at a time.  This way 
  147.  
  148. we don't lose time starting everything over again.
  149.  
  150.  
  151.      The second reason is inherent in the way Pascal handles I/O.  
  152.  
  153. When you call a Pascal READLN, you can ask it to read in any kind 
  154.  
  155. of data.  Integers, strings, booleans, reals, or records.  Not 
  156.  
  157. only that, but you have them in your READLN in any order, and in 
  158.  
  159. any quantity.  In other words, your I/O requests can be as sloppy 
  160.  
  161. as you want them to be.
  162.  
  163.  
  164.      So if you use the following READLN--->READLN (in_File, 
  165.  
  166. An_Integer1, A_Real1, A_String1, A_Boolean, A_Real2);<--- then 
  167.  
  168. you're asking for time trouble.  It has to first see if In_File is 
  169.  
  170. a file variable or not, and then it has to go through each of the 
  171.  
  172. variables seeing what type they are and the specifics on how to 
  173.  
  174. read each of them in.  All this takes a lot of time.
  175.  
  176.  
  177.      With the Fast Read routines, we avoid all of that. It knows 
  178.  
  179. that it's only reading or writing in strings from a text file.  
  180.  
  181. It knows the maximum string size allready.  In other words, 
  182.  
  183. specialization is what makes this routine faster.  Of course it 
  184.  
  185. costs a few more bytes, but if you're doing a lot of reading from 
  186.  
  187. text files, it makes it worth it.  
  188.  
  189.  
  190.                        Development Details
  191.  
  192.  
  193.      These routines are all based on GEMDOS functions $3C, $3D, 
  194.  
  195. $3E, $3F, $40 (Create, Open, Close, Read, Write).  Allthough 
  196.  
  197. these GEMDOS functions have been described before, they have only 
  198.  
  199. been presented as a way to read in screen information, or large 
  200.  
  201. amounts of array information.  Nothing on how to extract or 
  202.  
  203. insert strings from a one dimensional array.
  204.  
  205.  
  206.      So I had the information on loading a plain vanilla one-
  207.  
  208. dimension array.  For strings, this is almost useless.  There's 
  209.  
  210. just to much information you have to keep track of to read in a 
  211.  
  212. string to have a bunch of individual variables.  So after 
  213.  
  214. figuring out what I needed to keep track of, I declared the 
  215.  
  216. following record: 
  217.  
  218.    Buffer = RECORD
  219.       Buffer_Contents : Contents ; { Contents of the buffer.        }
  220.       File_Handle : INTEGER ; {      File handle.                   }
  221.       Error_Number : INTEGER ; {     Error Number if error occured. }
  222.       No_Error : BOOLEAN ; {         Was there no error occuring?   }
  223.       Buffer_Pos : LONG_INTEGER ; {  Position to be read next.      }
  224.       Buffer_Len : LONG_INTEGER ; {  How long is the buffer?        }
  225.       Last_Buffer : BOOLEAN ; {      Is this the last buffer?       }
  226.       Eof_Buffer : BOOLEAN ; {       Are we at the end of the file? }
  227.       Reading_File : BOOLEAN ; {     Are we reading this file?      }
  228.       Fast_Return : CHAR ; {         Return character.              }
  229.       Fast_Line_Feed : CHAR ; {      Line feed character.           }
  230.     END ; {of type buffer}
  231.  
  232.  
  233.      Now all I had to do was pass a single variable around, 
  234.  
  235. instead two or eight variables.  (Also a neat way to speed up the 
  236.  
  237. routines.)  
  238.  
  239.  
  240.      Next, I had to write the GEMDOS calls, F_Create, F_Open, 
  241.  
  242. F_Read, F_Write, and F_Close.  These came out of the O.S.S. 
  243.  
  244. release on using GEMDOS calls.  (Available on their BBS, BIX, and 
  245.  
  246. CIS.)
  247.  
  248.  
  249.      Then came the tricky part, writting the F_Reset, F_Rewrite, 
  250.  
  251. F_Readln, and F_Writeln routines.  F_Rewrite convertws the file 
  252.  
  253. name into C format and the calls F_Create (GEMDOS $3C.)  It then 
  254.  
  255. initializes it's variables depending on whether an error occurred 
  256.  
  257. or not.
  258.  
  259.  
  260.      F_Reset wasn't to hard once I figured out what I wanted it 
  261.  
  262. to do.  It has to convert the file name into C format in order to 
  263.  
  264. pass it correctly.  It then calls GEMDOS $3D to open the file.  
  265.  
  266. If it opens without an error, it then loads the Buffer_Contents 
  267.  
  268. array.
  269.  
  270.  
  271.      The F_Read_File routine is where we load the buffer.  If it 
  272.  
  273. successfully loads the buffer, it initializes the variables in the 
  274.  
  275. record.  It then checks to see if it was the end of the file, and 
  276.  
  277. sets Last_Buffer to TRUE or FALSE, as is appropriate.  If an error 
  278.  
  279. occurs, it sets all the variables to show this occurance.
  280.  
  281.  
  282.      The hard part was to write the F_Readln routine.  The first 
  283.  
  284. part I wrote was the area to just move characters from the buffer 
  285.  
  286. to the text string until we hit the last position in the buffer, 
  287.  
  288. or a Carriage Return character, or the string is filled.  
  289.  
  290.  
  291.      Then came the IF-THEN-ELSE statements to determine what to do 
  292.  
  293. next.  The first in the series checks to see if the loop was left 
  294.  
  295. because it found a Return.  If this was the case, it sets the 
  296.  
  297. length of the string equal to Counter.  It then increments the 
  298.  
  299. Buffer_Pos by two to pass the Return and the Line Feed.  If 
  300.  
  301. Buffer_Pos is greater than the length of the buffer it reloads 
  302.  
  303. the buffer again with a call to F_Read_File.  It then resets 
  304.  
  305. Buffer_Pos to one or two to set the position to the first 
  306.  
  307. character in the buffer.  It sets it to one if the first 
  308.  
  309. character isn't a Line Feed, and to two if it is.
  310.  
  311.  
  312.      If the program flow falls through the above test, it checks 
  313.  
  314. the next IF/THEN.  This checks to see if the loop was exited 
  315.  
  316. because the string was full.  If this was the case, then it sets 
  317.  
  318. the length of the string equal to counter and leaves Buffer_Pos 
  319.  
  320. alone.
  321.  
  322.  
  323.      If the programs passes that IF/THEN it checks to see if the 
  324.  
  325. string loading was interupted because it ran out of buffer, and 
  326.  
  327. there was more information in the file (Not Last_Buffer.)  If this 
  328.  
  329. was the case it reloads the buffer again and calls itself to 
  330.  
  331. finish reading the file.  If an error occurs while reloading the 
  332.  
  333. buffer, it sets the string length to Count, and exits the routine.
  334.  
  335.  
  336.      And lastly, it checks if the loop was done because it ran out 
  337.  
  338. of buffer and there wasn't any more information in the file.  If 
  339.  
  340. this was the case, it sets the string length to Count again, and 
  341.  
  342. sets EOF_Buffer to true.  It then exits the routine. 
  343.  
  344.  
  345.      The next set of routines are the Fast_Write routines.  These 
  346.  
  347. were written after the Fast_Read routines were done.  (Hence the 
  348.  
  349. program name.)  These routines are F_Writeln and F_Write.
  350.  
  351.  
  352.      F_Writeln was initially the F_Readln routine.  I copied it 
  353.  
  354. once and modified it a bit.  Instead of pulling characters from 
  355.  
  356. the main array (Buffer_Contents) it pushes them onto it.  This 
  357.  
  358. allowed me to remove one of the loop tests (Look for Return) 
  359.  
  360. since there wasn't a Return in sight.  When it exits the loop it 
  361.  
  362. sets Buffer_Len to the new length.  If there's more room in 
  363.  
  364. Buffer_Contents it pushes a Ruturn/Line Feed onto the array.  
  365.  
  366. Otherwise, it writes out the array and adds a Return/Line Feed 
  367.  
  368. combination onto the start of the next array.
  369.  
  370.  
  371.      The F_Eof, F_Error, and F_Error_Number routines were written 
  372.  
  373. just to help hide the data structure a little better.  A user 
  374.  
  375. could (if s/he is really desperate to save time.) directly access 
  376.  
  377. the contents of the record instead of calling these routines.  
  378.  
  379.  
  380.      But I just finished a programming class where the teacher was 
  381.  
  382. big on "Hiding Data Structures"  So I decided to hide the 
  383.  
  384. structure a little bit.  That, and it makes it easier to convert 
  385.  
  386. my programs over to these routines.  All I had to do was a global 
  387.  
  388. search and replace through my files to change Pascal routines into 
  389.  
  390. Fast routines.
  391.  
  392.  
  393.      For a weekend project, this wasn't to hard to finish up.  I 
  394.  
  395. think that this program shows a little bit more of the range of 
  396.  
  397. things that can be accomplished with O.S.S. Pascal.  With access 
  398.  
  399. like this to the internal TOS and GEM routines, Who needs C?  
  400.  
  401. Certainly not me!
  402.  
  403.  
  404. References:
  405.  
  406.     Personal Pascal
  407.      O.S.S.
  408.      1221B Kentwood Avenue
  409.      San Jose, CA, 95129
  410.      408-446-3099
  411.  
  412.